package com.tiancheng.onecode.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiancheng.onecode.entity.MemberOrder;
import com.tiancheng.onecode.entity.MemberOrderRefund;
import com.tiancheng.onecode.entity.MemberSubOrder;
import com.tiancheng.onecode.entity.PlatformMerchantSettleRule;
import com.tiancheng.onecode.enums.OrderStatusEnum;
import com.tiancheng.onecode.enums.RefundStatusEnum;
import com.tiancheng.onecode.exception.AssertException;
import com.tiancheng.onecode.exception.Asserts;
import com.tiancheng.onecode.mapper.MemberOrderRefundMapper;
import com.tiancheng.onecode.model.dto.PayMerchantDTO;
import com.tiancheng.onecode.model.request.admin.QueryOrderRefundReq;
import com.tiancheng.onecode.model.request.admin.RefundOrderReq;
import com.tiancheng.onecode.model.request.admin.StatisticsMerchantOrderReq;
import com.tiancheng.onecode.model.request.admin.StatisticsUserOrderReq;
import com.tiancheng.onecode.model.response.PageInfo;
import com.tiancheng.onecode.model.response.admin.*;
import com.tiancheng.onecode.model.response.api.RefundPreQueryReq;
import com.tiancheng.onecode.service.*;
import com.tiancheng.onecode.trade.TradeApiClient;
import com.tiancheng.onecode.trade.model.request.order.OpenRefundVO;
import com.tiancheng.onecode.trade.model.response.OpenRefundCreateResVO;
import com.tiancheng.onecode.trade.notify.RefundDetailResultMsgBO;
import com.tiancheng.onecode.trade.notify.RefundResultMsgBO;
import com.tiancheng.onecode.trade.utils.MoneyUtil;
import com.tiancheng.onecode.trade.utils.OrderIdHelper;
import com.tiancheng.onecode.utils.lock.Lock;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Author: kellen
 * @Description: 会员订单退款 service 实现类
 * @Date: create in 2024/12/23 20:05
 */
@Slf4j
@Service
public class MemberOrderRefundServiceImpl extends ServiceImpl<MemberOrderRefundMapper, MemberOrderRefund> implements IMemberOrderRefundService {

    @Resource
    private IBillService IBillService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private IMerchantService merchantService;
    @Resource
    private OrderIdHelper orderIdHelper;
    @Resource
    private TradeApiClient tradeApiClient;
    @Resource
    private IPlatformService platformService;
    @Resource
    private IPlatformMerchantSettleRuleService platformMerchantSettleRuleService;

    @Override
    public PageInfo<QueryOrderRefundRes> queryPlatformPage(QueryOrderRefundReq params) {
        IPage<MemberOrderRefund> page = new Page<>(params.getCurrentPage(), params.getPageSize());
        if (null != params.getCreateDtBegin()) {
            params.setCreateDtBegin(LocalDateTime.of(LocalDate.from(params.getCreateDtBegin()), LocalDateTime.MIN.toLocalTime()));
        }
        if (null != params.getCreateDtEnd()) {
            params.setCreateDtEnd(LocalDateTime.of(LocalDate.from(params.getCreateDtEnd()), LocalDateTime.MAX.toLocalTime()));
        }
        final IPage<QueryOrderRefundRes> pageResult = this.baseMapper.queryPage(page, params);
        if (CollectionUtils.isNotEmpty(pageResult.getRecords())) {
            List<PlatformQueryRes> platformQueryRes = platformService.queryByPlatformCodes(pageResult.getRecords().stream().map(QueryOrderRefundRes::getPlatformCode).collect(Collectors.toSet()));
            if (CollectionUtils.isNotEmpty(platformQueryRes)) {
                for (QueryOrderRefundRes record : pageResult.getRecords()) {
                    record.setBusinessName("聚合支付一码通");
                    platformQueryRes.stream().filter(p -> p.getPlatformCode().equals(record.getPlatformCode())).findFirst().ifPresent(p -> {
                        record.setPayChannelName(p.getPaymentChannelName());
                    });

                }
            }
        }
        return new PageInfo<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal(), pageResult.getRecords());
    }

    @Override
    public List<MemberOrderRefund> queryByOrderId(String orderId) {
        return this.list(new LambdaQueryWrapper<MemberOrderRefund>().eq(MemberOrderRefund::getOrderId, orderId));
    }

    @Override
    public QueryOrderRefundRes queryByRefundId(String refundId) {
        List<QueryOrderRefundRes> refundResList = this.baseMapper.queryByRefundId(refundId);
        if (CollectionUtils.isNotEmpty(refundResList) && StringUtils.isNotEmpty(refundResList.get(0).getSettleRuleCode())) {
            PlatformMerchantSettleRule platformMerchantSettleRule = platformMerchantSettleRuleService.queryByCode(refundResList.get(0).getSettleRuleCode());
            if (null != platformMerchantSettleRule) {
                refundResList.get(0).setPlatformPercent(platformMerchantSettleRule.getPlatformPercent());
            }

        }
        return CollectionUtils.isEmpty(refundResList) ? null : refundResList.get(0);
    }

    @Override
    public List<StatisticsMerchantOrderPayRes> statisticsByMerchant(StatisticsMerchantOrderReq statisticsMerchantOrderReq) {
        return this.baseMapper.statisticsByMerchant(statisticsMerchantOrderReq);
    }

    @Override
    public List<StatisticsMerchantOrderPayRes> statisticsByDay(StatisticsMerchantOrderReq statisticsMerchantOrderReq) {
        return this.baseMapper.statisticsByDay(statisticsMerchantOrderReq);
    }

    @Override
    public List<StatisticsUserOrderItemRes> statisticsByUserId(StatisticsUserOrderReq statisticsUserOrderReq) {
        return this.baseMapper.statisticsByUserId(statisticsUserOrderReq);
    }

    @Override
    public void refundResultHandler(RefundResultMsgBO refundResultMsgBO) {
        final List<MemberOrderRefund> refunds = this.list(new LambdaQueryWrapper<MemberOrderRefund>().eq(MemberOrderRefund::getRefundId, refundResultMsgBO.getRefundId()));
        if (CollectionUtils.isEmpty(refunds)) {
            log.warn("未查询到退款订单！退款单号：{}", refundResultMsgBO.getRefundId());
            return;
        }
        final List<MemberOrderRefund> updateRefunds = new ArrayList<>();
        for (MemberOrderRefund refund : refunds) {
            MemberOrderRefund updateRefund = new MemberOrderRefund();
            updateRefund.setId(refund.getId());
            final Optional<RefundDetailResultMsgBO> first = refundResultMsgBO.getSubRefunds().stream().filter(r -> r.getSubRefundId().equals(refund.getSubRefundId())).findFirst();
            if (first.isPresent()) {
                updateRefund.setRefundTime(refundResultMsgBO.getRefundTime());
                updateRefund.setFlowId(refundResultMsgBO.getFlowId());
                updateRefund.setRefundAmount(first.get().getAmount());
                updateRefund.setRefundStatus(first.get().getStatus());
                updateRefund.setLastUpdDt(LocalDateTime.now());
                updateRefunds.add(updateRefund);
            }
        }
        // 子订单集合
        List<MemberSubOrder> subOrders = getMemberSubOrderService().list(new LambdaQueryWrapper<MemberSubOrder>().in(MemberSubOrder::getSubOrderId, refunds.stream().map(MemberOrderRefund::getSubOrderId).collect(Collectors.toList())));
        final Boolean result = transactionTemplate.execute(transactionStatus -> {
            try {
                // 更新退款单
                if (CollectionUtils.isNotEmpty(updateRefunds)) {
                    this.updateBatchById(updateRefunds);
                }
                // 生成退款账单
                IBillService.createAfterRefund(refundResultMsgBO.getRefundId(),subOrders);
                // 判断订单是否全退了
                List<MemberOrderRefund> allRefunds = this.list(new LambdaQueryWrapper<MemberOrderRefund>().in(MemberOrderRefund::getSubOrderId, subOrders.stream().map(MemberSubOrder::getSubOrderId).collect(Collectors.toList())));
                // 判断是否全额退款，全额退款设置订单为已完成状态
                List<MemberOrder> memberOrders = new ArrayList<>();
                allRefunds.stream().collect(Collectors.groupingBy(MemberOrderRefund::getSubOrderId)).forEach((subOrderId,rs)->{
                    int subOrderRefundTotal = rs.stream().mapToInt(MemberOrderRefund::getRefundApplyAmount).sum();
                    MemberSubOrder memberSubOrder = subOrders.stream().filter(s->s.getSubOrderId().equals(subOrderId)).findFirst().get();
                    if(subOrderRefundTotal==memberSubOrder.getSubOrderAmount()){
                        MemberOrder memberOrder = new MemberOrder();
                        memberOrder.setOrderStatus(OrderStatusEnum.Completed.getCode());
                        memberOrder.setLastUpdDt(LocalDateTime.now());
                        getMemberOrderService().update(memberOrder,new LambdaQueryWrapper<MemberOrder>().eq(MemberOrder::getOrderId,rs.get(0).getOrderId()).eq(MemberOrder::getOrderStatus,OrderStatusEnum.paid.getCode()));
                        MemberSubOrder updateMemberSubOrder = new MemberSubOrder();
                        updateMemberSubOrder.setId(memberSubOrder.getId());
                        updateMemberSubOrder.setSubOrderStatus(OrderStatusEnum.Completed.getCode());
                        updateMemberSubOrder.setLastUpdDt(LocalDateTime.now());
                        getMemberSubOrderService().updateById(updateMemberSubOrder);
                    }
                });
                return true;
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                throw e;
            }
        });
        Asserts.isTrue(null != result && result, "退款消息处理异常！");
    }

    @Override
    public String refund(RefundOrderReq orderReq) {
        MemberOrder order = getMemberOrderService().queryByOrderId(orderReq.getOrderId());
        List<MemberSubOrder> memberSubOrders = getMemberSubOrderService().queryByOrderId(orderReq.getOrderId());
        Asserts.isTrue(memberSubOrders.get(0).getSubOrderStatus().equals(OrderStatusEnum.paid.getCode()), "订单当前状态不允许退款！");
        Asserts.isTrue(null != order && order.getOrderStatus().equals(OrderStatusEnum.paid.getCode()), "订单不存在或订单当前状态不允许退款！");
        try (Lock lock = new Lock(Lock.LOCK_ORDER_PAY, order.getUserId(), 5, 5)) {
            Asserts.isTrue(lock.getLockRes(), "退款失败，请稍后再试！");
            List<MemberOrderRefund> list = this.list(new LambdaQueryWrapper<MemberOrderRefund>().eq(MemberOrderRefund::getOrderId, orderReq.getOrderId()).ne(MemberOrderRefund::getRefundStatus, RefundStatusEnum.fail.getCode()));
            final boolean b = MoneyUtil.judgeTwoDecimal(orderReq.getRefundAmount());
            Asserts.isTrue(b, "金额异常！");
            // 转换金额单位到分
            final int amount = orderReq.getRefundAmount().multiply(new BigDecimal(100)).intValue();
            int sumRefundAmount = list.stream().mapToInt(MemberOrderRefund::getRefundApplyAmount).sum();
            Asserts.isTrue(sumRefundAmount + amount <= order.getOrderAmount(), "订单金额超出可退限制！");
            // 调用交易中台退款
            final PayMerchantDTO payMerchantDTO = merchantService.queryPayMerchant(order.getPlatformMerchantId());
            Asserts.isTrue(Objects.nonNull(payMerchantDTO) && StringUtils.isNotEmpty(payMerchantDTO.getQr()), "该商户配置异常，请联系管理员处理！");
            OpenRefundVO openRefundVO = new OpenRefundVO();
            openRefundVO.setUid(order.getUserId());
            openRefundVO.setOrderId(order.getOrderId());
            openRefundVO.setRefundId(orderIdHelper.getRefund(payMerchantDTO.getTradeIdPre(), order.getUserId()));
            openRefundVO.setCreateTime(LocalDateTime.now());
            openRefundVO.setRefundReason(orderReq.getRefundReason());
            List<OpenRefundVO.SubOrder> subOrders = new ArrayList<>();

            List<MemberSubOrder> sos = getMemberSubOrderService().queryByOrderId(order.getOrderId());
            OpenRefundVO.SubOrder subOrder = new OpenRefundVO.SubOrder();
            subOrder.setSubOrderId(sos.get(0).getSubOrderId());
            subOrder.setSubRefundId(openRefundVO.getRefundId() + "01");
            subOrder.setRefundAmount(amount);
            subOrders.add(subOrder);
            openRefundVO.setSubOrders(subOrders);

            log.info("调用交易中台退款：{}", openRefundVO);
            OpenRefundCreateResVO refundRes = tradeApiClient.refund(openRefundVO);
            log.info("调用交易中台退款，返回：{}", refundRes);
            MemberOrderRefund memberOrderRefund = new MemberOrderRefund();
            memberOrderRefund.setRefundId(openRefundVO.getRefundId());
            memberOrderRefund.setSubRefundId(subOrder.getSubRefundId());
            memberOrderRefund.setOrderId(order.getOrderId());
            memberOrderRefund.setSubOrderId(subOrder.getSubOrderId());
            memberOrderRefund.setPaymentId(refundRes.getPaymentId());
            memberOrderRefund.setUserId(order.getUserId());
            memberOrderRefund.setRefundApplyAmount(amount);
            memberOrderRefund.setDiscount(0);
            memberOrderRefund.setRefundStatus(RefundStatusEnum.ing.getCode());
            memberOrderRefund.setRefundReason(orderReq.getRefundReason());
            memberOrderRefund.setCreatedDt(LocalDateTime.now());
            this.save(memberOrderRefund);
            return memberOrderRefund.getRefundId();
        } catch (AssertException e) {
            throw e;
        } catch (Exception e) {
            log.error("退款失败：", e);
            throw new AssertException(500, "退款超时，请稍后再试！");
        }
    }

    @Override
    public RefundPreQueryReq refundPreQuery(String orderId) {
        MemberOrder order = getMemberOrderService().queryByOrderId(orderId);
        RefundPreQueryReq refundPreQueryReq = new RefundPreQueryReq();
        refundPreQueryReq.setOrderId(order.getOrderId());
        refundPreQueryReq.setOrderAmount(order.getOrderAmount());
        List<MemberSubOrder> memberSubOrders = getMemberSubOrderService().queryByOrderId(orderId);
        if (!memberSubOrders.get(0).getSubOrderStatus().equals(OrderStatusEnum.paid.getCode())) {
            // 状态在不在待清分，可以退款=0
            refundPreQueryReq.setAllowRefundAmount(0);
            return refundPreQueryReq;
        }
        List<MemberOrderRefund> list = this.list(new LambdaQueryWrapper<MemberOrderRefund>().eq(MemberOrderRefund::getOrderId, orderId).ne(MemberOrderRefund::getRefundStatus, RefundStatusEnum.fail.getCode()));
        // 转换金额单位到分
        int sumRefundAmount = list.stream().mapToInt(MemberOrderRefund::getRefundApplyAmount).sum();

        refundPreQueryReq.setAllowRefundAmount(order.getOrderAmount() - sumRefundAmount);
        return refundPreQueryReq;
    }

    private IMemberOrderService getMemberOrderService() {
        return SpringUtil.getBean(IMemberOrderService.class);
    }

    private IMemberSubOrderService getMemberSubOrderService() {
        return SpringUtil.getBean(IMemberSubOrderService.class);
    }
}
